package com.itcodai.utils.time;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

/**
 * @author c-fanqj
 * @date 2024/3/10
 * @apiNote 获取时间 控制任务执行顺序
 */
public class TimeControlTaskSequence {

    private static final Logger logger = LoggerFactory.getLogger(TimeControlTaskSequence.class);

    public static void main(String[] args) {
        //controlTaskSequence();
        //controlTaskSequence2();
        //controlTaskSequence3();
        //controlTaskSequence4();
        //controlTaskSequence5();
        controlTaskSequence6();
    }

    //  等待方法一执行完毕后，延迟执行方法二
    public static void controlTaskSequence6() {
        logger.info("任务开始执行");
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        // 方法一的任务
        Runnable task1 = () -> {
            // 执行方法一的逻辑
            logger.info("Executing Task 1 start");
            try {
                Thread.sleep(30000); // 3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("Executing Task 1 end");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        // 方法二的任务
        Runnable task2 = () -> {
            // 执行方法二的逻辑
            logger.info("Executing Task 2 start");
            try {
                Thread.sleep(5000); // 3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("Executing Task 2 end");
        };
        // 延迟执行方法一的时间
        long delayMethod1 = 10; // 假设延迟10秒执行方法一
        // 延迟执行方法二的时间
        long delayMethod2 = 20; // 方法一执行完后，再延迟20秒执行方法二
        // 使用 CompletableFuture 来顺序执行任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            // 延迟执行方法一
            //logger.info("方法1执行开始");
            executor.schedule(task1, delayMethod1, TimeUnit.SECONDS);
            //logger.info("方法1执行结束");
            // 等待方法一执行完毕后，延迟执行方法二
            /*try {
                TimeUnit.SECONDS.sleep(8);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            //logger.info("方法2执行开始");
            executor.schedule(task2, delayMethod2, TimeUnit.SECONDS);
            //logger.info("方法2执行结束");
        });
        //logger.info("执行开始");
        // 等待 CompletableFuture 完成
        future.join();
        //logger.info("执行开始2");
        // 关闭线程池
        executor.shutdown();
        //logger.info("执行开始3");

        /*21:38:29.155 [main] INFO  c.i.u.time.TimeControlTaskSequence - 任务开始执行
        21:38:39.237 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - Executing Task 1 start
        21:39:09.247 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - Executing Task 1 end
        21:39:14.258 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - Executing Task 2 start
        21:39:19.269 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - Executing Task 2 end*/
    }

    public static void controlTaskSequence5() {
        logger.info("任务开始处理");
        firstMethod();
        secondMethod();
        logger.info("任务处理结束");

        /*12:17:12.367 [main] INFO  c.i.u.time.TimeControlTaskSequence - 任务开始处理
        12:17:12.371 [main] INFO  c.i.u.time.TimeControlTaskSequence - 方法1开始处理
        12:17:12.462 [main] INFO  c.i.u.time.TimeControlTaskSequence - 方法1处理结束
        12:17:12.463 [main] INFO  c.i.u.time.TimeControlTaskSequence - 方法2开始处理
        12:17:12.463 [main] INFO  c.i.u.time.TimeControlTaskSequence - 方法2处理结束
        12:17:12.463 [main] INFO  c.i.u.time.TimeControlTaskSequence - 任务处理结束
        12:17:22.466 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 执行耗时方法1...
        12:17:22.466 [pool-2-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 执行耗时方法2...
        12:17:25.484 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 耗时方法1执行完成
        12:17:27.482 [pool-2-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 耗时方法2执行完成*/
    }

    public static void firstMethod() {
        logger.info("方法1开始处理");
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        Runnable task = () -> {
            // 执行耗时操作
            logger.info("执行耗时方法1...");
            // 模拟耗时操作
            try {
                Thread.sleep(3000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("耗时方法1执行完成");
        };
        long delay = calculateDelay();
        scheduler.schedule(task, delay, TimeUnit.MILLISECONDS); // 毫秒
        logger.info("方法1处理结束");
    }

    public static void secondMethod() {
        logger.info("方法2开始处理");
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        Runnable task = () -> {
            // 执行耗时操作
            logger.info("执行耗时方法2...");
            // 模拟耗时操作
            try {
                Thread.sleep(5000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("耗时方法2执行完成");
        };
        long delay = calculateDelay();
        scheduler.schedule(task, delay, TimeUnit.MILLISECONDS); // 毫秒
        logger.info("方法2处理结束");
    }

    //
    public static void controlTaskSequence4() {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        // 调度执行第一个方法
        executor.schedule(() -> {
            // 执行第一个耗时方法
            firstTimeConsumingMethod();

            // 第一个方法执行完后，调度执行第二个方法
            executor.schedule(() -> {
                // 执行第二个耗时方法
                secondTimeConsumingMethod();
            }, delayForSecondMethod(), TimeUnit.MILLISECONDS);
        }, delayForFirstMethod(), TimeUnit.MILLISECONDS);
    }

    // 第一个耗时方法
    private static void firstTimeConsumingMethod() {
        // 执行耗时操作
        System.out.println("Executing first time-consuming method...");
    }

    // 第二个耗时方法
    private static void secondTimeConsumingMethod() {
        // 执行耗时操作
        System.out.println("Executing second time-consuming method...");
    }

    // 计算第一个方法的延迟时间
    private static long delayForFirstMethod() {
        // 返回延迟时间，单位为毫秒
        return 1000; // 例如，延迟1秒
    }

    // 计算第二个方法的延迟时间
    private static long delayForSecondMethod() {
        // 返回延迟时间，单位为毫秒
        return 2000; // 例如，延迟2秒
    }

    // 多任务控制顺序
    public static void controlTaskSequence3() {
        logger.info("开始执行任务...");
        // 第一个任务
        CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {
            // 执行耗时操作
            logger.info("执行耗时方法...");
            // 模拟耗时操作
            try {
                Thread.sleep(2000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("耗时方法执行完成");
        });

        // 第二个任务
        CompletableFuture<Void> task2 = task1.thenRun(() -> {
            // 执行下一个方法
            logger.info("执行下一个方法...");
            try {
                Thread.sleep(5000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("执行结束下一个方法...");
        });

        // 在两个任务完成后执行下面的操作
        CompletableFuture<Void> finalTask = task2.thenRun(() -> {
            // 执行下面的操作
            logger.info("执行下面方法操作...");
            try {
                Thread.sleep(8000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("执行下面方法操作结束...");
        });
        logger.info("执行全部执行结束");
        // 等待所有任务完成
        finalTask.join();

        /*12:03:17.861 [main] INFO  c.i.u.time.TimeControlTaskSequence - 开始执行任务...
        12:03:17.961 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 执行耗时方法...
        12:03:17.962 [main] INFO  c.i.u.time.TimeControlTaskSequence - 执行全部执行结束
        12:03:19.975 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 耗时方法执行完成
        12:03:19.975 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 执行下一个方法...
        12:03:24.984 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 执行结束下一个方法...
        12:03:24.985 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 执行下面方法操作...
        12:03:32.994 [ForkJoinPool.commonPool-worker-9] INFO  c.i.u.time.TimeControlTaskSequence - 执行下面方法操作结束...*/
    }

    // 控制任务的执行顺序：任务1完成后，查看任务2是否要开始执行 根据最初的时间设计
    public static void controlTaskSequence2() {
        // 创建一个ScheduledExecutorService实例
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        // 定义第一个任务
        Runnable task1 = () -> {
            // 执行耗时操作
            logger.info("执行耗时方法...");
            // 模拟耗时操作
            try {
                Thread.sleep(5000); // 2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("耗时方法执行完成");
        };
        // 定义第二个任务
        Runnable task2 = () -> {
            logger.info("开始执行当前任务，当前时间-{}", getLocalDateTime());
            logger.info("执行下一个方法...");
        };
        logger.info("开始执行第一个任务，当前时间-{}", getLocalDateTime());
        // 延迟2秒后执行第一个任务
        executor.schedule(task1, 2, TimeUnit.SECONDS); // 秒
        logger.info("开始执行第二个任务，当前时间-{}", getLocalDateTime());
        // 在第一个任务完成后，理论上根据开始时间延迟10s执行第二个任务 定时
        executor.schedule(task2, 10, TimeUnit.SECONDS);
       /* ScheduledExecutorService executor2 = Executors.newScheduledThreadPool(1);
        executor2.schedule(task2, 3, TimeUnit.SECONDS);
        executor2.shutdown();*/
        // 关闭executor
        executor.shutdown();

        /*11:48:26.213 [main] INFO  c.i.u.time.TimeControlTaskSequence - 开始执行第一个任务，当前时间-2024-03-10 11:48:26
        11:48:26.253 [main] INFO  c.i.u.time.TimeControlTaskSequence - 开始执行第二个任务，当前时间-2024-03-10 11:48:26
        11:48:28.261 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 执行耗时方法...
        11:48:33.274 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 耗时方法执行完成
        11:48:36.267 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 开始执行当前任务，当前时间-2024-03-10 11:48:36
        11:48:36.269 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 执行下一个方法...*/
    }

    // 在特定时间执行任务 异步
    public static void controlTaskSequence() {
        logger.info("开始执行任务，当前时间-{}", getLocalDateTime());
        // 创建一个调度线程池
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        // 设置要执行的任务
        Runnable task = () -> {
            // 在这里编写要在特定时间执行的代码
            logger.info("在特定时间执行的任务");
            try {
                Thread.sleep(5*1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("在特定时间结束的任务");
        };
        // 计算距离特定时间的延迟时间
        long delay = calculateDelay();
        // 在特定时间执行任务 异步
        scheduler.schedule(task, delay, TimeUnit.MILLISECONDS); // 毫秒
        logger.info("结束任务，当前时间-{}", getLocalDateTime());

       /* 11:33:58.691 [main] INFO  c.i.u.time.TimeControlTaskSequence - 开始执行任务，当前时间-2024-03-10 11:33:58
        11:33:58.717 [main] INFO  c.i.u.time.TimeControlTaskSequence - 结束任务，当前时间-2024-03-10 11:33:58
        11:34:08.731 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 在特定时间执行的任务
        11:34:13.733 [pool-1-thread-1] INFO  c.i.u.time.TimeControlTaskSequence - 在特定时间结束的任务*/
    }

    // 计算距离特定时间的延迟时间
    private static long calculateDelay() {
        // 这里可以根据需要计算延迟时间，例如计算当前时间到目标时间的毫秒数
        // 这里只是一个示例，返回固定的延迟时间
        return 10000; // 10秒钟
    }

    public static String getLocalDateTime() {
        LocalDateTime dateTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = dateTime.format(formatter);
        return formattedDateTime;
    }

}
